#ifndef BOARD_HPP
#define BOARD_HPP

#include <vector>
#include <cstring>
#include <initializer_list>

namespace gomoku{

    struct point { // 表示一个格子的坐标
        int row;
        int col;
    };
    

    // point结构体的一些运算，行为和你想的一样
    inline point operator +(const point &pnt1, const point &pnt2);
    inline point operator -(const point &pnt1, const point &pnt2);
    inline point operator -(const point &pnt);
    inline bool operator ==(const point &pnt1, const point &pnt2);
    inline bool operator !=(const point &pnt1, const point &pnt2);
    
    enum class point_status{ // 表示棋盘上一个格子的状态
        vacant, // 空白
        black, // 有黑子
        white, // 有白子
        disabled, // 格子被禁用
    };

    struct board_event{ // 描述棋盘上的一个变化
        point pos; // 发生改变的格子
        point_status event; // 格子改变之后的状态
        point_status before; // 格子改变之前的状态
    };
    
    class board{ // 描述棋盘的对象
        private:
            int _width,_height;
            int _black_cnt,_white_cnt,_disabled_cnt;
            point_status *_points; // 用于内部存储棋盘的各个格子状态
            std::vector<board_event> _change_log;
        public:
            board(int height, int width);
            board(int height, int width, point_status *raw_layout_array);
            ~board();
            void place_black(point pos); // 放置黑子,注意这个函数不会检查格子是否可用就直接设置状态
            void place_white(point pos); // 放置白子
            void clear_point(point pos); // 将格子设定为空白状态
            void disable_point(point pos); // 禁用格子
            inline int height() const; // 高度
            inline int width() const; // 宽度
            inline int black_conut() const; // 黑子数目
            inline int white_count() const; // 白子数目
            inline int stone_count() const; // 棋子总数
            inline int disabled_count() const; // 被禁用的格子总数
            inline int vacant_count() const; // 空白的格子总数 
            void (*on_event)(board &Board)=nullptr; //棋盘上发生变化时触发这个函数
            point_status operator [](point pos) const; // 可以用下标运算符只读访问棋盘上的格子
            const std::vector<board_event> &change_log = this->_change_log; // 改动记录
            inline const point_status* raw_layout() const;
    };
    
    class pattern{ // 用于匹配棋盘上的模式
        private:
    
        public:
            struct glob{ // 描述模式中的一个格子
                bool positive; // 如果为真，则该匹配是指定状态的格子，如果为假，则匹配不是指定状态的格子
                point pos; // 格子相对于左上角的位置
                point_status status; // 指定格子的状态
            };
            pattern();
            pattern(std::initializer_list<glob> glob_list);
            std::vector<glob> glob_list;
            bool match(const board &Board, const point &pos) const; // 判断某一个格子是否与该特征匹配
            point find(const board &Board) const; // 在棋盘上寻找特征，返回该特征首次出现的位置，如未找到则返回（-1,-1）
    };

    inline point operator-(const point &pnt){
        return point{-pnt.row,-pnt.col};
    }
    
    inline point operator +(const point &pnt1, const point &pnt2){
        return point{pnt1.row+pnt2.row,pnt1.col+pnt2.col};
    }

    inline point operator -(const point &pnt1, const point &pnt2){
        return point{pnt1.row-pnt2.row,pnt1.col-pnt2.col};
    }

    inline bool operator ==(const point &pnt1, const point &pnt2){
        return pnt1.row==pnt2.row && pnt1.col==pnt2.col;
    }

    inline bool operator !=(const point &pnt1, const point &pnt2){
        return !(pnt1==pnt2);
    }

    inline const point_status* board::raw_layout() const{
        return _points;
    }

    inline int board::height() const{
        return _height;
    }

    inline int board::width() const{
        return _width;
    }

    inline int board::black_conut() const{
        return _black_cnt;
    }

    inline int board::white_count() const{
        return _white_cnt;
    }

    inline int board::stone_count() const{
        return white_count()+black_conut();
    }

    inline int board::disabled_count() const{
        return _disabled_cnt;
    }

    inline int board::vacant_count() const{
        return width()*height()-_black_cnt-_white_cnt-_disabled_cnt;
    }

}

#endif